package com.ihr360.excel.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ihr360.authority.embed.base.entity.AuthStaffDataRequest;
import com.ihr360.commons.exception.Ihr360SpreadSheetAsynException;
import com.ihr360.commons.lang.CollectionUtils;
import com.ihr360.commons.lang.StringUtils;
import com.ihr360.commons.vo.ResultInfo;
import com.ihr360.excel.ExcelUtil;
import com.ihr360.excel.annotation.InterruptIgnore;
import com.ihr360.excel.constants.ExcelDefaultConfig;
import com.ihr360.excel.context.ExcelContext;
import com.ihr360.excel.convertor.ExcelLogToJournal;
import com.ihr360.excel.dao.CorrectSpreadsheetRowRepository;
import com.ihr360.excel.dao.RegistryBusinessModuleRepository;
import com.ihr360.excel.dao.SpreadSheetRepository;
import com.ihr360.excel.dao.SpreadsheetJournalRepository;
import com.ihr360.excel.entity.CorrectSpreadsheetRowEntity;
import com.ihr360.excel.entity.ImportParams;
import com.ihr360.excel.entity.SpreadsheetJournalEntity;
import com.ihr360.excel.logs.ExcelCommonLog;
import com.ihr360.excel.logs.ExcelLogItem;
import com.ihr360.excel.logs.ExcelLogType;
import com.ihr360.excel.logs.ExcelLogs;
import com.ihr360.excel.logs.ExcelRowLog;
import com.ihr360.excel.model.dto.CorrectSpreadsheetRow;
import com.ihr360.excel.model.dto.RegistryBusinessModule;
import com.ihr360.excel.model.dto.SpreadSheet;
import com.ihr360.excel.model.dto.SpreadsheetJournal;
import com.ihr360.excel.model.type.JournalType;
import com.ihr360.excel.model.type.SpreadSheetStatus;
import com.ihr360.excel.service.ExcelService;
import com.ihr360.excel.service.Ihr360StaffApiService;
import com.ihr360.excel.service.IrenshiFileDubboService;
import com.ihr360.excel.service.SpreadsheetJournalService;
import com.ihr360.excel.service.SpreadsheetService;
import com.ihr360.excel.service.ValidatorFeignService;
import com.ihr360.excel.service.convertor.SpreadsheetJournalConvertor;
import com.ihr360.excel.service.convertor.SpreadsheetRowConvertor;
import com.ihr360.excel.specification.ColumnSpecification;
import com.ihr360.excel.specification.CommonSpecification;
import com.ihr360.excel.type.ProgressStep;
import com.ihr360.excel.vo.CustomSpreadSheetValidateResult;
import com.ihr360.excel.vo.ImportResult;
import com.ihr360.excel.vo.ProgressContext;
import com.ihr360.excel.vo.ProgressContextFile;
import com.ihr360.excel.vo.ProgressResult;
import com.ihr360.excel.vo.SpreadSheetCell;
import com.ihr360.excel.vo.SpreadSheetRow;
import com.ihr360.excel.vo.SpreadSheetSpecification;
import com.ihr360.excel.vo.SpreadSheetValidInterruptError;
import com.ihr360.excel.vo.SpreadSheetValidatorError;
import com.ihr360.excel.vo.SpreadSheetValidatorRequest;
import com.ihr360.excel.vo.StaffUniqueVo;
import com.ihr360.feign.interceptor.AuthUserInfoInterceptor;
import com.ihr360.sharedservice.api.DataCacheService;
import feign.hystrix.HystrixFeign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class ExcelServiceImpl implements ExcelService {

    Logger logger = LoggerFactory.getLogger(ExcelServiceImpl.class);

    @Autowired
    private IrenshiFileDubboService irenshiFileDubboService;

    @Autowired
    private SpreadSheetRepository spreadSheetRepository;

    @Autowired
    private CorrectSpreadsheetRowRepository correctSpreadsheetRowRepository;

    @Autowired
    private DataCacheService dataCacheService;

    @Autowired
    private SpreadsheetJournalRepository spreadsheetJournalRepository;

    @Autowired
    private SpreadsheetJournalService spreadsheetJournalService;

    @Autowired
    private SpreadsheetJournalConvertor spreadsheetJournalConvertor;

    @Autowired
    private SpreadsheetRowConvertor spreadsheetRowConvertor;

    @Autowired
    private SpreadsheetService spreadsheetService;

    @Autowired
    private RegistryBusinessModuleRepository registryBusinessModuleRepository;

    @Autowired
    private Ihr360StaffApiService ihr360StaffApiService;


    @Override
    @InterruptIgnore
    public void doHandleExcelFileProcess(ProgressContext progressContext) {

        RegistryBusinessModule registryBusinessModule = registryBusinessModuleRepository.findByCode(progressContext.getModuleCode());
        checkResigtryModule(progressContext, registryBusinessModule);

        ProgressContextFile file = getBinaryFile(progressContext);
        logger.info("Excel处理流程：成功从文件服务获取文件");
        dataCacheService.put(progressContext.getProgressKey(), ProgressStep.UPLOAD.getProgress());
        ExcelLogs logs = new ExcelLogs();
        ValidatorFeignService validatorFeignService = getValidatorFeignService(registryBusinessModule);

        //----------------------------------获取通用校验规则，并进行校验－－－－－－－－－－－－－－－－－－－－－－－
        SpreadSheetSpecification spreadSheetSpecification = getSpreadSheetSpecification(progressContext, validatorFeignService);
        ImportParams<Map> importParams = getMapImportParams(spreadSheetSpecification);
        ExcelContext excelContext = new ExcelContext();
        Collection<Map> excelDatas = ExcelUtil.importExcel(importParams, new ByteArrayInputStream(file.getBytes()), logs, excelContext);
        logger.info("Excel处理流程：完成Excel文件解析");
        dataCacheService.put(progressContext.getProgressKey(), "50");

        SpreadSheet spreadSheet = spreadsheetService.getOrAndCurrentSpreadsheet(progressContext);
        setDateColumns(spreadSheet, importParams.getColumnSpecifications());

        Date currentDate = spreadSheet.getCreatedAt();
        //处理解析结果
        handlerExcelParseError(progressContext, logs, spreadSheet);
        if (logs.hasExcelLogs()) {
            spreadsheetService.save(spreadSheet);
            return;
        }
        dataCacheService.put(progressContext.getProgressKey(), "55");

        //60 获取excel解析得到的数据
        getCorrectSpreadsheetRows(excelDatas, currentDate, importParams.getCommonSpecification(), progressContext, spreadSheet);
//        spreadSheet = spreadSheetRepository.save(spreadSheet);
        dataCacheService.put(progressContext.getProgressKey(), "60");
        logger.info("Excel处理流程：完成Excel中间文件存储");

        boolean enableMatchStaff = spreadSheetSpecification.getCommonSpecification().isEnableMatchStaff();
        dataCacheService.put(progressContext.getProgressKey(), ProgressStep.PARSE.getProgress());
        List<SpreadsheetJournal> noMatchStaffJournals = Lists.newArrayList();

        //匹配员工 75
        List<StaffUniqueVo> haveStaffIdVos = doMatchStaffIdProcessor(progressContext, enableMatchStaff, noMatchStaffJournals, spreadSheet);
//        spreadSheet = spreadSheetRepository.save(spreadSheet);

        if (CollectionUtils.isEmpty(haveStaffIdVos) && enableMatchStaff) {
            spreadSheetRepository.save(spreadSheet);
            dataCacheService.put(progressContext.getProgressKey(), ProgressStep.FINISH.getProgress());
            return;
        }
        dataCacheService.put(progressContext.getProgressKey(), "80");

        List<SpreadsheetJournal> noPermissionStaffJournals = Lists.newArrayList();
        //处理员工访问权限
        if (enableMatchStaff && CollectionUtils.isNotEmpty(haveStaffIdVos)) {
            List<CorrectSpreadsheetRow> matchStaffRows = spreadSheet.getRows().stream()
                    .filter(r -> StringUtils.isNotEmpty(r.getStaffId()))
                    .collect(Collectors.toList());
            if (CollectionUtils.isEmpty(matchStaffRows)) {
                spreadSheetRepository.save(spreadSheet);
                dataCacheService.put(progressContext.getProgressKey(), ProgressStep.FINISH.getProgress());
                return;
            }
            doHandleStaffAccessAuthority(progressContext, haveStaffIdVos, noPermissionStaffJournals, spreadSheet);
//            spreadSheet = spreadSheetRepository.save(spreadSheet);
        }

        List<CorrectSpreadsheetRow> permissionRows = spreadSheet.getRows().stream().filter(r -> r.getHasPermission()).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(permissionRows)) {
            spreadSheetRepository.save(spreadSheet);
            dataCacheService.put(progressContext.getProgressKey(), ProgressStep.FINISH.getProgress());
            return;
        }
        dataCacheService.put(progressContext.getProgressKey(), "85");


        //调用业务校验
        ExcelLogs customValidateLog = new ExcelLogs();
        doCustomValidate(validatorFeignService,
                progressContext,
                registryBusinessModule,
                customValidateLog,
                excelDatas,
                spreadSheet,
                spreadSheetSpecification.getCommonSpecification(), haveStaffIdVos);

        dataCacheService.put(progressContext.getProgressKey(), "90");
        List<SpreadsheetJournal> customValidateJournals = getSpreadsheetJournals(customValidateLog, progressContext.getCompanyId());
        spreadSheet.getJournals().addAll(customValidateJournals);
        if (CollectionUtils.isNotEmpty(customValidateJournals)) {
            for (SpreadsheetJournal customValidateJournal : customValidateJournals) {
                customValidateJournal.setSheet(spreadSheet);
            }
        }
        spreadSheet = spreadsheetService.save(spreadSheet);
        dataCacheService.put(progressContext.getProgressKey(), "95");

        //生成带错误信息的文件
        List<ExcelRowLog> noMatchStaffLogs = getRowLogsFromJournal(noMatchStaffJournals, progressContext);
        List<ExcelRowLog> noPermissionLogs = getRowLogsFromJournal(noPermissionStaffJournals, progressContext);
        logs.getRowLogList().addAll(customValidateLog.getRowLogList());
        logs.getRowLogList().addAll(noMatchStaffLogs);
        logs.getRowLogList().addAll(noPermissionLogs);
        generateErrorField(progressContext, file, logs, spreadSheet, excelContext);
        dataCacheService.put(progressContext.getProgressKey(), ProgressStep.FINISH.getProgress());

    }


    @Override
    @InterruptIgnore
    public void saveExcelProcessorJournal(ProgressContext progressContext, String errorMsg) {
        SpreadSheet spreadSheet = spreadsheetService.getOrAndCurrentSpreadsheet(progressContext);
        saveCommonJournal(progressContext, errorMsg, spreadSheet);
    }

    @Override
    @InterruptIgnore
    public void saveExcelProcessorJournal(ProgressContext progressContext,
                                          String errorMsg,
                                          String msgKey,
                                          Object[] args,
                                          JournalType journalType) {
        SpreadSheet spreadSheet = spreadsheetService.getOrAndCurrentSpreadsheet(progressContext);
        SpreadsheetJournal spreadsheetJournal
                = SpreadsheetJournal.getJournal(journalType, msgKey, errorMsg, args, progressContext.getProgressKey());
        spreadsheetJournal.setLogType(ExcelLogType.CUSTOM_LOG_TYPE);
        spreadsheetJournal.setSheet(spreadSheet);
        spreadsheetJournal.setCompanyId(progressContext.getCompanyId());
        spreadsheetJournalRepository.save(spreadsheetJournal);
    }

    @Override
    @InterruptIgnore
    public ProgressResult getProgressResult(ProgressContext progressContext) {
        String progress = dataCacheService.get(progressContext.getProgressKey());
        ProgressResult result = new ProgressResult();

        if (StringUtils.isEmpty(progress)) {
            result.setProgress("0");
            result.setCurrentStep(1);
            result.setStepProgress("0");
        } else {
            Integer currentStep = ProgressStep.getCurrentStep(Integer.parseInt(progress));
            result.setCurrentStep(currentStep);
            String progressStep = ProgressStep.getStepProgress(Integer.parseInt(progress));
            result.setStepProgress(progressStep);
            result.setProgress(progress);
            result.setStepSuccess(true);
        }
        List<SpreadsheetJournal> commonLogs = spreadsheetJournalService.getCurrentInterruptLog(progressContext);

        if (CollectionUtils.isNotEmpty(commonLogs)) {
            List<SpreadsheetJournalEntity> journalEntities = spreadsheetJournalConvertor.convertDtosToEntities(commonLogs);
            result.setErrorLog(journalEntities);
            result.setStepSuccess(false);
        }

        return result;
    }

    @Override
    public ImportResult getImportResult(ProgressContext progressContext) {
        ImportResult result = new ImportResult();
        SpreadSheet spreadSheet = spreadsheetService.getCurrentSpreadsheet(progressContext);
        if (spreadSheet == null || (CollectionUtils.isEmpty(spreadSheet.getRows()) && CollectionUtils.isEmpty(spreadSheet.getJournals()))) {
            return result;
        }
        result.setHasErrorFile(StringUtils.isNotEmpty(spreadSheet.getErrorFileId()));
        result.setHasCommentFile(StringUtils.isNotEmpty(spreadSheet.getCommentsFileId()));

        List<SpreadsheetJournal> journals = spreadSheet.getJournals();
        List<Integer> journalRowNums = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(journals)) {
            journals = journals.stream().filter(j -> j.getType() != JournalType.INTERRUPTLOG).collect(Collectors.toList());
            journalRowNums = journals.stream().map(SpreadsheetJournal::getRowNum).collect(Collectors.toList());
        }

        List<CorrectSpreadsheetRow> list = new ArrayList<>();
        for (CorrectSpreadsheetRow row : spreadSheet.getRows()) {
            if (row.getHasPermission() && !journalRowNums.contains(row.getRowNum())) {
                list.add(row);
            }
        }
        List<CorrectSpreadsheetRowEntity> entities = spreadsheetRowConvertor.convertDtosToEntities(list, spreadSheet.getDateHeaders());
        List<SpreadsheetJournalEntity> journalEntities = spreadsheetJournalConvertor.convertDtosToEntities(journals);
        Map<Integer, List<SpreadsheetJournalEntity>> rowJournalMap = journalEntities.stream()
                .filter(j -> j.getRowNum() != null)
                .collect(Collectors.groupingBy(SpreadsheetJournalEntity::getRowNum));
        List<SpreadsheetJournalEntity> resultJournals = Lists.newArrayList();
        rowJournalMap.forEach((rowNum, rowJournals) -> {
            SpreadsheetJournalEntity journal = new SpreadsheetJournalEntity();
            BeanUtils.copyProperties(rowJournals.get(0), journal);
            String logMsg = rowJournals.stream().map(SpreadsheetJournalEntity::getDefaultLogMsg).collect(Collectors.joining(";"));
            journal.setDefaultLogMsg(logMsg);
            resultJournals.add(journal);
        });
        resultJournals.addAll(journalEntities.stream().filter(j -> j.getRowNum() == null).collect(Collectors.toList()));

        resultJournals.sort(Comparator.comparing(j -> j.getRowNum()));
        result.setCorrectDatas(entities);
        result.setRowLogs(resultJournals);
        result.setConvertResult(spreadSheet.getConvertResult());
        result.setDateHeaders(spreadSheet.getDateHeaders());
        return result;
    }

    @Override
    @Transactional
    @InterruptIgnore
    public ResultInfo interruptProgress(ProgressContext progressContext) {
        logger.info("－－－－－－－－－－－－执行放弃导入－－－－－－－－－－－－");
        spreadsheetService.fineshedHistory(progressContext.getProgressKey());
        dataCacheService.remove(progressContext.getProgressKey());
        return new ResultInfo.Builder<>().success();
    }

    @Override
    @InterruptIgnore
    public String getErrorFileId(ProgressContext progressContext) {
        SpreadSheet spreadSheet = null;
        if (progressContext.isOnlyErrorDownload()) {
            spreadSheet = spreadSheetRepository.findLastFinishSpreSheet(progressContext.getProgressKey());
        } else {
            spreadSheet = spreadSheetRepository.findByProgressKeyAndStatus(progressContext.getProgressKey(), SpreadSheetStatus.INPROGRESS);
        }

        if (spreadSheet == null) {
            return null;
        }
        if (progressContext.isOnlyErrorDownload()) {
            if (StringUtils.isEmpty(spreadSheet.getErrorFileId())) {
                return null;
            }
            return spreadSheet.getErrorFileId();
        } else {
            if (StringUtils.isEmpty(spreadSheet.getCommentsFileId())) {
                return null;
            }
            return spreadSheet.getCommentsFileId();
        }
    }

    /**
     * 匹配员工Id
     *
     * @param
     * @param progressContext
     * @param enableMatchStaff
     * @param noMatchStaffJournals
     * @param spreadSheet
     * @return
     */
    private List<StaffUniqueVo> doMatchStaffIdProcessor(final ProgressContext progressContext,
                                                        boolean enableMatchStaff,
                                                        final List<SpreadsheetJournal> noMatchStaffJournals,
                                                        final SpreadSheet spreadSheet) {

        if (!enableMatchStaff) {
            return Lists.newArrayList();
        }

        // 通过姓名 + 手机号 匹配员工  （确定是否关联员工的导入都以姓名+手机唯一标识）
        List<StaffUniqueVo> getStaffIdVos = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(spreadSheet.getRows())) {
            spreadSheet.getRows().forEach(row -> {
                StaffUniqueVo staffUniqueVo = new StaffUniqueVo();
                staffUniqueVo.setMobileNo(row.getMobileNo());
                staffUniqueVo.setStaffName(row.getStaffName());
                staffUniqueVo.setCompanyId(progressContext.getCompanyId());
                getStaffIdVos.add(staffUniqueVo);
            });
        }
        List<StaffUniqueVo> haveStaffIdVos = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(getStaffIdVos)) {
            haveStaffIdVos = irenshiFileDubboService.getStaffInfo(getStaffIdVos, progressContext.getProgressKey());
        }
        logger.info("Excel处理流程：已从花名册获取员工姓名+手机号信息");

        dataCacheService.put(progressContext.getProgressKey(), "70");

        //处理Excel中间数据，设置staffId
        if (CollectionUtils.isNotEmpty(haveStaffIdVos)) {

            Map<String, List<StaffUniqueVo>> staffNameMap = haveStaffIdVos.stream().collect(Collectors.groupingBy(StaffUniqueVo::getStaffName));

            spreadSheet.getRows().forEach(row -> {
                List<StaffUniqueVo> staffUniqueVos = staffNameMap.get(row.getStaffName());

                if (CollectionUtils.isNotEmpty(staffUniqueVos)) {
                    if (staffUniqueVos.size() == 1 && StringUtils.isNotEmpty(staffUniqueVos.get(0).getStaffId())) {
                        row.setStaffId(staffUniqueVos.get(0).getStaffId());
                    } else {

                        Map<String, String> haveStaffInfoMap = staffUniqueVos.stream()
                                .collect(Collectors.toMap(StaffUniqueVo::getUniqueKey, StaffUniqueVo::getStaffId));

                        if (StringUtils.isEmpty(row.getMobileNo())) {
                            SpreadsheetJournal journal = getMultiMatchedStaffJournal(progressContext, spreadSheet, row);
                            noMatchStaffJournals.add(journal);
                        } else {
                            String staffId = haveStaffInfoMap.get(row.getStaffName() + row.getMobileNo());
                            if (StringUtils.isNotEmpty(staffId)) {
                                row.setStaffId(staffId);
                            } else {
                                SpreadsheetJournal journal = getNotMatchedStaffJournal(progressContext, spreadSheet, row);
                                noMatchStaffJournals.add(journal);
                            }
                        }
                    }
                } else {
                    SpreadsheetJournal journal = getNotMatchedStaffJournal(progressContext, spreadSheet, row);
                    noMatchStaffJournals.add(journal);
                }
            });
        } else {
            spreadSheet.getRows().forEach(row -> {
                SpreadsheetJournal journal = getNotMatchedStaffJournal(progressContext, spreadSheet, row);
                noMatchStaffJournals.add(journal);
            });
        }
        spreadSheet.getJournals().addAll(noMatchStaffJournals);

        dataCacheService.put(progressContext.getProgressKey(), "75");
        logger.info("Excel处理流程：完成员工与Excel数据匹配");
        return haveStaffIdVos;
    }

    private SpreadsheetJournal getMultiMatchedStaffJournal(ProgressContext progressContext, SpreadSheet spreadSheet, CorrectSpreadsheetRow row) {
        SpreadsheetJournal journal = new SpreadsheetJournal();
        journal.setSheet(spreadSheet);
        journal.setProgressKey(progressContext.getProgressKey());
        journal.setCompanyId(progressContext.getCompanyId());
        journal.setType(JournalType.COMMONLOG);
        journal.setLogMsgKey("Multi_matching_employee");
        journal.setDefaultLogMsg("根据姓名配到多个员工数据,请提供手机号");
        journal.setLogType(ExcelLogType.CUSTOM_LOG_TYPE);
        journal.setCreatedAt(new Date());
        journal.setUpdatedAt(new Date());
        journal.setRowNum(row.getRowNum());
        journal.setColNum(progressContext.getMobileColNum());
        return journal;
    }

    private SpreadsheetJournal getNotMatchedStaffJournal(ProgressContext progressContext, SpreadSheet spreadSheet, CorrectSpreadsheetRow row) {
        SpreadsheetJournal journal = new SpreadsheetJournal();
        journal.setSheet(spreadSheet);
        journal.setProgressKey(progressContext.getProgressKey());
        journal.setCompanyId(progressContext.getCompanyId());
        journal.setType(JournalType.COMMONLOG);
        journal.setLogMsgKey("Not_matching_employee");
        journal.setDefaultLogMsg("未匹配到员工数据");
        journal.setLogType(ExcelLogType.CUSTOM_LOG_TYPE);
        journal.setCreatedAt(new Date());
        journal.setUpdatedAt(new Date());
        journal.setRowNum(row.getRowNum());
        return journal;
    }

    private SpreadsheetJournal getStaffNameRequireJournal(ProgressContext progressContext, final SpreadSheet spreadSheet, CorrectSpreadsheetRow row) {
        SpreadsheetJournal journal = new SpreadsheetJournal();
        journal.setSheet(spreadSheet);
        journal.setProgressKey(progressContext.getProgressKey());
        journal.setCompanyId(progressContext.getCompanyId());
        journal.setType(JournalType.COMMONLOG);
        journal.setLogMsgKey("StaffName_is_required");
        journal.setDefaultLogMsg("员工姓名列不能为空");
        journal.setLogType(ExcelLogType.CUSTOM_LOG_TYPE);
        journal.setCreatedAt(new Date());
        journal.setUpdatedAt(new Date());
        journal.setRowNum(row.getRowNum());
        journal.setColNum(progressContext.getStaffNameNum());
        return journal;
    }


    /**
     * 处理员工访问权限
     *
     * @param progressContext
     * @param haveStaffIdVos
     * @param noPermissionStaffJournals
     * @param spreadSheet
     */
    private void doHandleStaffAccessAuthority(ProgressContext progressContext, List<StaffUniqueVo> haveStaffIdVos,
                                              List<SpreadsheetJournal> noPermissionStaffJournals, final SpreadSheet spreadSheet) {
        List<String> matchedStaffIds = haveStaffIdVos.stream().map(StaffUniqueVo::getStaffId).collect(Collectors.toList());
        String code = progressContext.getModuleCode();
        RegistryBusinessModule registryBusinessModule = registryBusinessModuleRepository.findByCode(code);
        if (registryBusinessModule == null || StringUtils.isEmpty(registryBusinessModule.getAuthModuleCode())) {
            throw new Ihr360SpreadSheetAsynException(progressContext.getProgressKey(), "导入失败，请检查导入模块注册数据！");
        }
        String authModuleCode = registryBusinessModule.getAuthModuleCode();

        AuthStaffDataRequest authStaffDataRequest = new AuthStaffDataRequest();
        authStaffDataRequest.setStaffIdList(matchedStaffIds);
        authStaffDataRequest.setAuthorityCode(authModuleCode);
//        authStaffDataRequest.setAuthorityStaffStatus(AuthorityStaffStatus.IN_SERVICE);
        List<String> canAccessStaffIds = ihr360StaffApiService.getCanAccessStaffIdList(progressContext.getCompanyId(), progressContext.getUserId(), authStaffDataRequest);
        if (CollectionUtils.isEmpty(canAccessStaffIds)) {
            canAccessStaffIds = Lists.newArrayList();
        }
        for (CorrectSpreadsheetRow row : spreadSheet.getRows()) {
            String staffId = row.getStaffId();
            boolean hasAccessAuthority = org.apache.commons.lang.StringUtils.isNotEmpty(staffId)
                    && canAccessStaffIds.contains(staffId);
            if (hasAccessAuthority) {
                row.setHasPermission(true);
            } else {
                if (!matchedStaffIds.contains(staffId)) {
                    continue;
                }
                SpreadsheetJournal journal = new SpreadsheetJournal();
                journal.setSheet(spreadSheet);
                journal.setProgressKey(progressContext.getProgressKey());
                journal.setCompanyId(progressContext.getCompanyId());
                journal.setType(JournalType.COMMONLOG);
                journal.setLogMsgKey("No_permission_to_import_the_employee");
                journal.setDefaultLogMsg("没有导入员工" + row.getStaffName() + "的权限");
                journal.setLogType(ExcelLogType.CUSTOM_LOG_TYPE);
                journal.setCreatedAt(new Date());
                journal.setUpdatedAt(new Date());
                journal.setRowNum(row.getRowNum());
                noPermissionStaffJournals.add(journal);
            }
        }
        spreadSheet.getJournals().addAll(noPermissionStaffJournals);
        logger.info("Excel处理流程：完成员工导入权限处理");
    }

    private ProgressContextFile getBinaryFile(ProgressContext progressContext) {
        if (StringUtils.isEmpty(progressContext.getFileId())) {
            throw new Ihr360SpreadSheetAsynException(progressContext.getProgressKey(), "文件处理失败，唯一标识不能为空！");
        }

        ProgressContextFile file = irenshiFileDubboService.getFile(progressContext.getFileId(), progressContext.getProgressKey());
        if (file == null) {
            throw new Ihr360SpreadSheetAsynException(progressContext.getProgressKey(), "文件处理失败，获取文件失败！");
        }
        return file;
    }

    @InterruptIgnore
    private void saveCommonJournal(ProgressContext progressContext, String defaultLogMsg, SpreadSheet spreadSheet) {
        SpreadsheetJournal journal = new SpreadsheetJournal();
        journal.setSheet(spreadSheet);
        journal.setProgressKey(progressContext.getProgressKey());
        journal.setCompanyId(progressContext.getCompanyId());
        journal.setType(JournalType.INTERRUPTLOG);
        journal.setDefaultLogMsg(defaultLogMsg);
        journal.setLogType(ExcelLogType.CUSTOM_LOG_TYPE);
        journal.setCreatedAt(new Date());
        journal.setUpdatedAt(new Date());
        spreadsheetJournalRepository.save(journal);
    }

    /**
     * 获取excel解析得到的数据
     *
     * @param excelDatas
     * @param currentDate
     * @param commonSpecification
     * @param spreadSheet
     * @return
     */
    private List<CorrectSpreadsheetRow> getCorrectSpreadsheetRows(Collection<Map> excelDatas,
                                                                  Date currentDate,
                                                                  CommonSpecification commonSpecification,
                                                                  final ProgressContext progressContext, final SpreadSheet spreadSheet) {
        List<CorrectSpreadsheetRow> rows = Lists.newArrayList();
        boolean hasStaffNameAndMobileNoConfig = commonSpecification != null
                && CollectionUtils.isNotEmpty(commonSpecification.getStaffNameAlias())
                && CollectionUtils.isNotEmpty(commonSpecification.getMobileNoAlias());

        boolean enableMatchStaff = commonSpecification != null && commonSpecification.isEnableMatchStaff();
        if (enableMatchStaff && !hasStaffNameAndMobileNoConfig) {
            throw new Ihr360SpreadSheetAsynException(progressContext.getProgressKey(), "导入失败，缺少员工姓名和手机号的配置！");
        }
        List<String> nameAlias = commonSpecification.getStaffNameAlias();
        List<String> mobileAlias = commonSpecification.getMobileNoAlias();

        if (CollectionUtils.isNotEmpty(excelDatas)) {
            List<SpreadsheetJournal> staffNameRequiredJournals = Lists.newArrayList();
            for (Map excelData : excelDatas) {
                if (MapUtils.isEmpty(excelData)) {
                    continue;
                }
                CorrectSpreadsheetRow row = new CorrectSpreadsheetRow();
                String staffName = getAliasValue(excelData, nameAlias, progressContext, true);
                String mobileNo = getAliasValue(excelData, mobileAlias, progressContext, false);

                Integer rowNum = (Integer) excelData.get(ExcelDefaultConfig.COMMON_SPECIFICATION_ROWNUM);
                if (rowNum != null) {
                    row.setRowNum(rowNum);
                }
                row.setData(excelData);
                row.setMobileNo(mobileNo);
                row.setStaffName(staffName);
                row.setCompanyId(progressContext.getCompanyId());
                row.setCreatedAt(currentDate);
                row.setUpdatedAt(currentDate);
                if (!enableMatchStaff) {
                    row.setHasPermission(true);
                }
                if (enableMatchStaff && StringUtils.isEmpty(staffName)) {
                    SpreadsheetJournal journal = getStaffNameRequireJournal(progressContext, spreadSheet, row);
                    staffNameRequiredJournals.add(journal);
                }
                rows.add(row);
            }
            if (CollectionUtils.isNotEmpty(staffNameRequiredJournals)) {
                spreadSheet.getJournals().addAll(staffNameRequiredJournals);
            }

        }
        dataCacheService.put(progressContext.getProgressKey(), "60");
        spreadSheet.setRows(rows);
        if (CollectionUtils.isNotEmpty(rows)) {
            rows.forEach(row -> {
                row.setSheet(spreadSheet);
            });
        }

        return rows;
    }

    /**
     * @param excelData       行数据
     * @param headerAlias
     * @param progressContext
     * @return
     */
    private String getAliasValue(Map excelData, List<String> headerAlias, ProgressContext progressContext, boolean isStaffName) {
        if (MapUtils.isEmpty(excelData)) {
            return null;
        }

        Iterator it = excelData.entrySet().iterator();
        int i = 0;
        while (it.hasNext()) {
            Map.Entry entity = (Map.Entry) it.next();
            if (headerAlias.contains(entity.getKey())) {
                if (progressContext != null) {
                    if (isStaffName) {
                        progressContext.setStaffNameNum(i);
                    } else {
                        progressContext.setMobileColNum(i);
                    }
                }
                if (entity.getValue() == null) {
                    return null;
                }
                return String.valueOf(entity.getValue());
            }
            i++;
        }
        return null;
    }


    /**
     * 根据解析日志生成中间表日志记录
     *
     * @param logs
     * @param companyId
     * @return
     */
    private List<SpreadsheetJournal> getSpreadsheetJournals(ExcelLogs logs, String companyId) {
        List<SpreadsheetJournal> journals = Lists.newArrayList();
        if (logs.hasExcelLogs()) {
            ExcelCommonLog commonLog = logs.getExcelCommonLog();
            List<SpreadsheetJournal> commonJournals = ExcelLogToJournal.getJournals(commonLog.getExcelLogItems(), JournalType.INTERRUPTLOG, null, companyId);
            journals.addAll(commonJournals);
        }
        if (logs.hasRowLogList()) {
            logs.getRowLogList().forEach(rowLog -> {
                List<SpreadsheetJournal> rowJournals = ExcelLogToJournal.getJournals(rowLog.getExcelLogItems(), JournalType.COMMONLOG, rowLog.getRowNum(), companyId);
                journals.addAll(rowJournals);
            });
        }
        return journals;
    }

    private ImportParams<Map> getMapImportParams(SpreadSheetSpecification spreadSheetSpecification) {
        ImportParams<Map> importParams = new ImportParams<>();
        importParams.setImportType(Map.class);
        CommonSpecification commonSpecification = null;

        if (spreadSheetSpecification != null && spreadSheetSpecification.getCommonSpecification() != null) {
            commonSpecification = spreadSheetSpecification.getCommonSpecification();
            commonSpecification.setRowNumKey(ExcelDefaultConfig.COMMON_SPECIFICATION_ROWNUM);
            commonSpecification.setShowRowNum(true);
        } else {
            commonSpecification = CommonSpecification.createCommonSpecification(true);
            List<String> staffNameAlias = Lists.newArrayList("姓名", "名字");
            List<String> mobileNoAlias = Lists.newArrayList("手机号", "手机", "手机号码");
            commonSpecification.setStaffNameAlias(staffNameAlias);
            commonSpecification.setMobileNoAlias(mobileNoAlias);
        }

        importParams.setCommonSpecification(commonSpecification);
        if (spreadSheetSpecification != null && CollectionUtils.isNotEmpty(spreadSheetSpecification.getColumnSpecifications())) {
            importParams.setColumnSpecifications(spreadSheetSpecification.getColumnSpecifications());
        }
        return importParams;
    }

    private List<SpreadSheetRow> getSpreadSheetRows(Collection<Map> excelDatas,
                                                    CommonSpecification commonSpecification,
                                                    ProgressContext progressContext, List<StaffUniqueVo> haveStaffIdVos) {
        if (CollectionUtils.isEmpty(excelDatas)) {
            return Lists.newArrayList();
        }

        Map<Integer, SpreadSheetRow> spreadSheetRowMap = Maps.newHashMap();
        for (Map<String, Object> excelData : excelDatas) {
            Integer rowNum = (Integer) excelData.get(ExcelDefaultConfig.COMMON_SPECIFICATION_ROWNUM);
            SpreadSheetRow spreadSheetRow = spreadSheetRowMap.get(rowNum);

            String staffId = getStaffId(commonSpecification, progressContext, haveStaffIdVos, excelData);
            if (commonSpecification.isEnableMatchStaff() && StringUtils.isEmpty(staffId)) {
                continue;
            }

            if (spreadSheetRow == null) {
                spreadSheetRow = new SpreadSheetRow();
                spreadSheetRowMap.put(rowNum, spreadSheetRow);
                spreadSheetRow.setRowNum(rowNum);
                spreadSheetRow.setStaffId(staffId);
                spreadSheetRow.setCells(new ArrayList<>());
            }

            List<SpreadSheetCell> cells = spreadSheetRow.getCells();
            Iterator<String> iterator = excelData.keySet().iterator();
            int i = 0;
            while (iterator.hasNext()) {
                i++;
                String key = iterator.next();
                if (!ExcelDefaultConfig.COMMON_SPECIFICATION_ROWNUM.equals(key)) {
                    SpreadSheetCell cell = new SpreadSheetCell();
                    cell.setRowNum(rowNum);
                    cell.setColNum(i);
                    cell.setHeaderName(key);
                    cell.setCellValue(excelData.get(key));
                    cells.add(cell);
                }
            }
        }
        return Lists.newArrayList(spreadSheetRowMap.values());
    }

    /**
     * 获取业务校验结果
     *
     * @param validatorErrors
     * @param progressContext
     * @return
     */
    private List<ExcelRowLog> getCustomLogs(List<SpreadSheetValidatorError> validatorErrors, ProgressContext progressContext) {
        if (CollectionUtils.isEmpty(validatorErrors)) {
            return Lists.newArrayList();
        }

        Map<Integer, ExcelRowLog> excelRowLogMap = Maps.newHashMap();
        validatorErrors.forEach(validatorError -> {

            ExcelRowLog excelRowLog = excelRowLogMap.get(validatorError.getRowNum());
            if (excelRowLog == null) {
                excelRowLog = new ExcelRowLog();
                excelRowLog.setRowNum(validatorError.getRowNum());
                excelRowLogMap.put(validatorError.getRowNum(), excelRowLog);
            }

            List<ExcelLogItem> excelLogItems = excelRowLog.getExcelLogItems();
            if (excelLogItems == null) {
                excelLogItems = Lists.newArrayList();
                excelRowLog.setExcelLogItems(excelLogItems);
            }
            ExcelLogItem excelLogItem = new ExcelLogItem();
            excelLogItem.setColNum(validatorError.getColNum());
            excelLogItem.setDefaultLogMsg(validatorError.getMsg());
            excelLogItem.setLogType(ExcelLogType.CUSTOM_LOG_TYPE);
            excelLogItems.add(excelLogItem);
        });

        return Lists.newArrayList(excelRowLogMap.values());
    }

    /**
     * 进行业务校验
     *
     * @param validatorFeignService
     * @param progressContext
     * @param registryBusinessModule
     * @param logs
     * @param excelDatas
     * @param spreadSheet
     * @param commonSpecification
     * @param haveStaffIdVos
     */
    public void doCustomValidate(ValidatorFeignService validatorFeignService,
                                 ProgressContext progressContext,
                                 RegistryBusinessModule registryBusinessModule,
                                 ExcelLogs logs,
                                 Collection<Map> excelDatas,
                                 final SpreadSheet spreadSheet,
                                 CommonSpecification commonSpecification,
                                 List<StaffUniqueVo> haveStaffIdVos) {

        List<Map> correctMap = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(spreadSheet.getJournals())) {
            Set<Integer> journalRowNums = spreadSheet.getJournals().stream().map(SpreadsheetJournal::getRowNum).collect(Collectors.toSet());
            for (Map rowMap : excelDatas) {
                if (journalRowNums.contains(rowMap.get(ExcelDefaultConfig.COMMON_SPECIFICATION_ROWNUM))) {
                    continue;
                }
                correctMap.add(rowMap);
            }
        } else {
            correctMap = (List<Map>) excelDatas;
        }


        String moduleCode = progressContext.getModuleCode();
        boolean needCustomValid = StringUtils.isNotEmpty(registryBusinessModule.getBaseUrl())
                && StringUtils.isNotEmpty(moduleCode)
                && CollectionUtils.isNotEmpty(correctMap);
        if (needCustomValid) {
            SpreadSheetValidatorRequest request = new SpreadSheetValidatorRequest();
            request.setCompanyId(progressContext.getCompanyId());
            request.setModuleCode(progressContext.getModuleCode());
            List<SpreadSheetRow> spreadSheetDatas = getSpreadSheetRows(correctMap, commonSpecification, progressContext, haveStaffIdVos);
            request.setSpreadSheetDatas(spreadSheetDatas);
            request.setExtraParams(progressContext.getExtraParams());
            CustomSpreadSheetValidateResult validateResult = null;
            try {
                validateResult = validatorFeignService.validate(request);
            } catch (Exception e) {
                logger.error(e.toString());
                throw new Ihr360SpreadSheetAsynException(progressContext.getProgressKey(), "导入异常，业务校验失败");
            }

            if (validateResult != null && validateResult.getInterruptError() != null) {
                SpreadSheetValidInterruptError spreadSheetValidInterruptError = validateResult.getInterruptError();
                throw new Ihr360SpreadSheetAsynException(progressContext.getProgressKey()
                        , spreadSheetValidInterruptError.getDefaultLogMsg(),
                        spreadSheetValidInterruptError.getLogMsgKey(),
                        spreadSheetValidInterruptError.getArgs());
            }

            if (validateResult != null && validateResult.hasErrors()) {
                List<SpreadSheetValidatorError> validatorErrors = validateResult.getErrors();
                List<ExcelRowLog> customRowLogs = getCustomLogs(validatorErrors, progressContext);
                List<ExcelRowLog> excelRowLogs = logs.getRowLogList();
                if (excelRowLogs == null) {
                    excelRowLogs = Lists.newArrayList();
                    logs.setRowLogList(excelRowLogs);
                }
                excelRowLogs.addAll(customRowLogs);
            }

            if (validateResult != null && validateResult.getConvertResult() != null) {
                byte[] convertResult = validateResult.getConvertResult();
                spreadSheet.setConvertResult(convertResult);
            }
        }
    }

    /**
     * 生成错误文件
     *
     * @param progressContext
     * @param file
     * @param logs
     * @param spreadSheet
     * @param excelContext
     */
    private void generateErrorField(ProgressContext progressContext, ProgressContextFile file, ExcelLogs logs, SpreadSheet spreadSheet, ExcelContext excelContext) {
        if (logs.hasRowLogList()) {
            byte[] commentFileDatas = ExcelUtil.generateCommentFile(new BufferedInputStream(new ByteArrayInputStream(file.getBytes())), logs.getRowLogList(), false, excelContext);
            if (commentFileDatas != null) {
                ProgressContextFile commentFile = new ProgressContextFile(commentFileDatas, file.getOriginalFilename());
                ProgressContext tmpProgressContext = new ProgressContext();
                BeanUtils.copyProperties(progressContext, tmpProgressContext);
                tmpProgressContext.setFile(commentFile);
                String commentFileId = irenshiFileDubboService.saveExcel(tmpProgressContext);
                spreadSheet.setCommentsFileId(commentFileId);
            }
            byte[] errorFileDatas = ExcelUtil.generateCommentFile(new ByteArrayInputStream(file.getBytes()), logs.getRowLogList(), true, excelContext);

            if (errorFileDatas != null) {
                ProgressContextFile errorFile = new ProgressContextFile(errorFileDatas, file.getOriginalFilename());
                ProgressContext tmpProgressContext = new ProgressContext();
                BeanUtils.copyProperties(progressContext, tmpProgressContext);
                tmpProgressContext.setFile(errorFile);
                String errorFileId = irenshiFileDubboService.saveExcel(tmpProgressContext);
                spreadSheet.setErrorFileId(errorFileId);
            }
            spreadsheetService.save(spreadSheet);

        }
    }

    private ValidatorFeignService getValidatorFeignService(RegistryBusinessModule registryBusinessModule) {
        HystrixFeign.Builder builder = HystrixFeign.builder()
                .logLevel(feign.Logger.Level.FULL)
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .requestInterceptor(new AuthUserInfoInterceptor());

        return builder.target(ValidatorFeignService.class, registryBusinessModule.getBaseUrl());
    }

    private SpreadSheetSpecification getSpreadSheetSpecification(ProgressContext progressContext, ValidatorFeignService validatorFeignService) {
        dataCacheService.put(progressContext.getProgressKey(), "45");

        SpreadSheetValidatorRequest request = new SpreadSheetValidatorRequest();
        request.setCompanyId(progressContext.getCompanyId());
        request.setModuleCode(progressContext.getModuleCode());
        request.setExtraParams(progressContext.getExtraParams());
        SpreadSheetSpecification spreadSheetSpecification = null;
        try {
            spreadSheetSpecification = validatorFeignService.commonValidate(request);
        } catch (Exception e) {
            throw new Ihr360SpreadSheetAsynException(progressContext.getProgressKey(), "导入异常，获取校验规则失败！");
        }
        return spreadSheetSpecification;
    }

    private void checkResigtryModule(ProgressContext progressContext, RegistryBusinessModule registryBusinessModule) {
        if (registryBusinessModule == null) {
            SpreadSheet spreadSheet = spreadsheetService.getOrAndCurrentSpreadsheet(progressContext);
            saveCommonJournal(progressContext, "导入失败，配置模块不存在！", spreadSheet);
            logger.error("导入失败，配置模块不存在,moduleCode:{}", progressContext.getModuleCode());
            throw new Ihr360SpreadSheetAsynException(progressContext.getProgressKey(), "导入失败，配置模块不存在！");
        }
    }

    private void handlerExcelParseError(ProgressContext progressContext, final ExcelLogs logs, final SpreadSheet spreadSheet) {
        if (logs.hasExcelLogs()) {
            logger.info("Excel处理流程：解析出错，流程结束！");
            List<SpreadsheetJournal> journals = getSpreadsheetJournals(logs, progressContext.getCompanyId());
            spreadSheet.setJournals(journals);
            if (CollectionUtils.isNotEmpty(journals)) {
                journals.forEach(journal -> {
                    journal.setSheet(spreadSheet);
                    journal.setProgressKey(progressContext.getProgressKey());
                });
            }

        } else if (logs.hasRowLogList()) {
            List<SpreadsheetJournal> journals = getSpreadsheetJournals(logs, progressContext.getCompanyId());
            spreadSheet.setJournals(journals);
            if (CollectionUtils.isNotEmpty(journals)) {
                journals.forEach(journal -> {
                    journal.setSheet(spreadSheet);
                    journal.setProgressKey(progressContext.getProgressKey());
                });
            }
        }
    }

    private String getStaffId(CommonSpecification commonSpecification, ProgressContext progressContext, List<StaffUniqueVo> haveStaffIdVos, Map<String, Object> excelData) {
        List<String> nameAlias = Lists.newArrayList();
        List<String> mobileAlias = Lists.newArrayList();
        if (commonSpecification.isEnableMatchStaff()) {
            nameAlias = commonSpecification.getStaffNameAlias();
            mobileAlias = commonSpecification.getMobileNoAlias();
            if (CollectionUtils.isEmpty(nameAlias) || CollectionUtils.isEmpty(mobileAlias)) {
                throw new Ihr360SpreadSheetAsynException(progressContext.getProgressKey(), "导入失败，缺少员工姓名和手机号的配置！");
            }
        }
        String staffName = getAliasValue(excelData, nameAlias, progressContext, true);
        String mobileNo = getAliasValue(excelData, mobileAlias, progressContext, false);
        String staffId = "";


        Map<String, String> staffNameMobileNoUniqueMap = Maps.newHashMap();
        Map<String, String> staffNameUniqueMap = Maps.newHashMap();

        if (CollectionUtils.isNotEmpty(haveStaffIdVos)) {
            staffNameMobileNoUniqueMap = haveStaffIdVos.stream().collect(Collectors.toMap(s -> s.getStaffName() + "-" + s.getMobileNo(), s -> s.getStaffId()));
            for (StaffUniqueVo haveStaffIdVo : haveStaffIdVos) {
                staffNameUniqueMap.put(haveStaffIdVo.getStaffName(), haveStaffIdVo.getStaffId());
            }
        }

        if (StringUtils.isNotEmpty(staffName) && StringUtils.isNotEmpty(mobileNo)) {
            staffId = staffNameMobileNoUniqueMap.get(staffName + "-" + mobileNo);
        } else if (StringUtils.isNotEmpty(staffName)) {
            staffId = staffNameUniqueMap.get(staffName);
        }
        return staffId;
    }

    private List<ExcelRowLog> getRowLogsFromJournal(List<SpreadsheetJournal> noMatchStaffJournals, ProgressContext progressContext) {
        if (CollectionUtils.isEmpty(noMatchStaffJournals)) {
            return Lists.newArrayList();
        }
//        noMatchStaffJournals = noMatchStaffJournals.stream().filter(j -> j.getColNum() != null && j.getRowNum() != null).collect(Collectors.toList());
//        if (CollectionUtils.isEmpty(noMatchStaffJournals)) {
//            return Lists.newArrayList();
//        }
        List<ExcelRowLog> requiredMobileLogs = Lists.newArrayListWithCapacity(noMatchStaffJournals.size());

        Map<Integer, List<SpreadsheetJournal>> rowNumJournals = noMatchStaffJournals.stream().collect(Collectors.groupingBy(SpreadsheetJournal::getRowNum));

        rowNumJournals.forEach((rowNum, journals) -> {

            ExcelRowLog excelRowLog = new ExcelRowLog();
            excelRowLog.setRowNum(rowNum);

            List<ExcelLogItem> excelLogItems = Lists.newArrayListWithCapacity(journals.size());
            excelRowLog.setExcelLogItems(excelLogItems);
            requiredMobileLogs.add(excelRowLog);
            journals.forEach(j -> {
                ExcelLogItem excelLogItem = new ExcelLogItem();
                excelLogItem.setLogType(ExcelLogType.CUSTOM_LOG_TYPE);
                excelLogItem.setDefaultLogMsg(j.getDefaultLogMsg());
                excelLogItem.setLogMsgKey(j.getLogMsgKey());
                if (j.getColNum() == null) {
                    excelLogItem.setColNum(progressContext.getStaffNameNum());
                } else {
                    excelLogItem.setColNum(j.getColNum());
                }
                excelLogItem.setArgs(j.getArgs());
                excelLogItems.add(excelLogItem);
            });
        });
        return requiredMobileLogs;
    }


    /**
     * 设置日期列
     *
     * @param spreadSheet
     * @param columnSpecifications
     */
    private void setDateColumns(final SpreadSheet spreadSheet, final List<ColumnSpecification> columnSpecifications) {
        if (CollectionUtils.isEmpty(columnSpecifications)) {
            return;
        }
        Set<String> headers = columnSpecifications.stream().filter(c -> c.getCellType() != null && Date.class.equals(c.getCellType()))
                .map(c -> c.getColumns()).flatMap(h -> h.stream()).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(headers)) {
            return;
        }
        spreadSheet.setDateHeaders(Lists.newArrayList(headers));
    }

}
